package city.spring.controller.base;

import com.baomidou.mybatisplus.extension.api.ApiController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import lombok.Data;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 文件上传控制器（上传到七牛云存储）
 *
 * @author HouKunLin
 * @date 2020/1/8 0008 9:50
 */
@RestController
@RequestMapping("")
public class UploadController extends ApiController {
    /**
     * 上传文件服务器本地保存路径
     */
    private final File uploadDir;
    private final ObjectMapper objectMapper;
    /**
     * 七牛云存储区域
     */
    private final Region region = Region.region2();
    private final String bucketName = "hou-oss";
    private final String accessKey = "CrRHAkhHmCLkUTwPvUD4JIHQMpAxFYhXTIR1OlxR";
    private final String accessSecretKey = "iRv3SzpDgCM-EhnI_n1RT6tX-SlyqT6xEUG_S1e6";

    public UploadController(ObjectMapper objectMapper) throws Exception {
        this.objectMapper = objectMapper;
        String property = System.getProperty("os.name");
        System.out.println("当前系统类型：" + property);
        if (property.toLowerCase().contains("win")) {
            uploadDir = new File("C:/pension-system/upload/");
        } else {
            uploadDir = new File("/var/pension-system/upload/");
        }
        if (!uploadDir.exists()) {
            if (!uploadDir.mkdirs()) {
                throw new Exception("创建上传文件保存路径失败");
            }
        }
    }

    /**
     * 文件上传
     *
     * @param parts 文件列表
     * @return 返回格式如下：<code>
     * |{
     * |    "code": 0,
     * |    "data": [
     * |        {
     * |            "status": "ok",
     * |            "info": {
     * |                "domainName": "http://download.oss.houkunlin.cn",
     * |                "key": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
     * |                "size": 0,
     * |                "submittedFileName": "VM虚拟机共享文件夹.txt",
     * |                "contentType": "text/plain",
     * |                "url": "http://download.oss.houkunlin.cn/da39a3ee5e6b4b0d3255bfef95601890afd80709"
     * |            }
     * |        },
     * |        {
     * |            "status": "ok",
     * |            "info": {
     * |                "domainName": "http://download.oss.houkunlin.cn",
     * |                "key": "5b99e53027c54226665e456f1ecfd50e841343be",
     * |                "size": 466707,
     * |                "submittedFileName": "5b99e53027c54226665e456f1ecfd50e841343be.png",
     * |                "contentType": "image/png",
     * |                "url": "http://download.oss.houkunlin.cn/5b99e53027c54226665e456f1ecfd50e841343be"
     * |            }
     * |        }
     * |    ],
     * |    "msg": "执行成功"
     * |}
     * </code>
     */
    @PostMapping("/upload")
    public Object upload(@RequestPart("file") List<Part> parts) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (Part part : parts) {
            Map<String, Object> item = new LinkedHashMap<>();
            try {
                UploadResult uploadResult = saveFileToLocal(part, getPartSha1Hex(part));
                item.put("status", "ok");
                item.put("info", uploadResult);
            } catch (Exception e) {
                item.put("status", "error");
                item.put("info", new UploadResult(part, null));
                item.put("msg", e.getMessage());
            }
            list.add(item);
        }

        return success(list);
    }

    /**
     * 上传文件本地保存
     *
     * @param part 文件信息
     * @param key  保存key
     * @return 返回结果
     * @throws IOException 异常
     */
    @Deprecated
    private UploadResult saveFileLocal(Part part, String key) throws IOException {
        part.write(uploadDir.getAbsolutePath() + File.separator + key);

        return new UploadResult(part, key);
    }

    /**
     * 获得文件的 Sha1 值
     *
     * @param part 上传文件
     * @return 哈希值
     * @throws IOException 获取 InputStream 失败
     */
    private String getPartSha1Hex(Part part) throws IOException {
        InputStream inputStream = part.getInputStream();
        return DigestUtils.sha1Hex(inputStream);
    }

    /**
     * 上传文件，保存文件到七牛云存储
     *
     * @param part 文件
     * @param key  key
     * @return 结果
     * @throws IOException 异常
     */
    public UploadResult saveFileToQiniu(Part part, String key) throws IOException {
        UploadManager uploadManager = getUploadManager();
        String uploadToken = getUploadToken();
        // 默认不指定key的情况下，以文件内容的hash值作为文件名
        Response response = uploadManager.put(part.getInputStream(), key, uploadToken, null, part.getContentType());
        String bodyString = response.bodyString();
        // 解析上传成功的结果
        DefaultPutRet defaultPutRet = objectMapper.readValue(bodyString, DefaultPutRet.class);

        return new UploadResult(part, defaultPutRet.key);
    }

    public UploadManager getUploadManager() {
        // 构造一个带指定Region对象的配置类
        Configuration cfg = new Configuration(region);
        return new UploadManager(cfg);
    }

    private String getUploadToken() {
        // Token 默认有效期 3600
        // 在实际应用中，这个地方应该设置缓存
        Auth auth = Auth.create(accessKey, accessSecretKey);
        return auth.uploadToken(bucketName);
    }

    private UploadResult saveFileToLocal(Part part, String key) throws IOException {
        String submittedFileName = part.getSubmittedFileName();
        String ext = submittedFileName.substring(submittedFileName.lastIndexOf(".") + 1).toLowerCase();
        String saveFileName = key + "." + ext;
        String filepath = key.substring(0, 2).toUpperCase() + "/" + saveFileName;
        File file = new File(uploadDir, filepath);
        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {
            if (!parentFile.mkdirs()) {
                throw new RuntimeException("无法上传文件：创建上传文件保存路径失败");
            }
        }
        part.write(file.getAbsolutePath());
        UploadResult uploadResult = new UploadResult(part, filepath, "");
        uploadResult.setUrl("/files/" + filepath);
        return uploadResult;
    }

    /**
     * 上传结果
     *
     * @author HouKunLin
     * @date 2020/1/17 0017 16:01
     */
    @Data
    public static class UploadResult {
        private String domainName;
        private String key;
        private Long size;
        private String submittedFileName;
        private String contentType;
        private String url;

        public UploadResult(Part part, String key) {
            // 七牛云资源访问域名
            this(part, key, "http://download.oss.houkunlin.cn");
        }

        public UploadResult(Part part, String key, String domainName) {
            // 七牛云资源访问域名
            this.domainName = domainName;
            this.key = key;
            this.size = part.getSize();
            this.submittedFileName = part.getSubmittedFileName();
            this.contentType = part.getContentType();
            if (domainName != null) {
                this.url = String.format("%s/%s", domainName, key).replaceAll("(?<!(http:|https:))/+", "/");
            }
        }
    }
}
